package wangwenjun.phase2.concurrencypattern.producerconsumer.lockcondition;

import lombok.extern.slf4j.Slf4j;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author ChangLiang
 * @date 2020/6/22
 */
@Slf4j
public class EventQueue {

    static class Event{}

    private final int max;

    private final LinkedList<Event> eventQueue = new LinkedList<>();

    private final static int DEFAULT_MAX_EVENT = 10;

    public EventQueue(int max) {
        this.max = max;
    }

    public EventQueue() {
        this(DEFAULT_MAX_EVENT);
    }

    private final static ReentrantLock locker = new ReentrantLock();
    private final static Condition condition = locker.newCondition();

    public void offer(Event event) {
        try {
            locker.lock();
            while (eventQueue.size() >= this.max) {
                log.warn(" the queue is full.");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            eventQueue.addLast(event);
            log.info(" new event submitted:{}", event);
            condition.signalAll();
        }finally {
            locker.unlock();
        }
    }

    public Event take() {
        try {
            locker.lock();
            while (eventQueue.isEmpty()) {
                log.warn(" the queue is empty.");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Event event = eventQueue.removeFirst();
            log.debug(" the event   handled:{}", event);
            condition.signalAll();
            return event;
        }finally {
            locker.unlock();
        }
    }

    private final static Condition PRODUCER_CONDITION = locker.newCondition();

    private final static Condition CONSUMER_CONDITION = locker.newCondition();

    public void offerFair(Event event) {
        try {
            locker.lock();
            while (eventQueue.size() >= this.max) {
                log.warn(" the queue is full.");
                try {
                    PRODUCER_CONDITION.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            eventQueue.addLast(event);
            log.info(" new event submitted:{}", event);
            CONSUMER_CONDITION.signalAll();
        }finally {
            locker.unlock();
        }
    }

    public Event takeFair() {
        try {
            locker.lock();
            while (eventQueue.isEmpty()) {
                log.warn(" the queue is empty.");
                try {
                    CONSUMER_CONDITION.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Event event = eventQueue.removeFirst();
            log.debug(" the event   handled:{}", event);
            PRODUCER_CONDITION.signalAll();
            return event;
        }finally {
            locker.unlock();
        }
    }
}
